package com.hirsi.common.core.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.ContentType;
import com.hirsi.common.core.annotation.RequestBodyParam;
import com.hirsi.common.core.convert.RequestMessageConverter;
import com.hirsi.common.core.exception.ServerRuntimeException;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import javax.servlet.ServletRequest;
import java.util.ArrayList;
import java.util.List;

public class RequestMethodProcessor implements HandlerMethodArgumentResolver {

    private ServletModelAttributeMethodProcessor formResolver;

    private RequestResponseBodyMethodProcessor jsonResolver;

    private List<ContentType> contentTypes;

    public RequestMethodProcessor() {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        messageConverters.add(new RequestMessageConverter());
        formResolver = new ServletModelAttributeMethodProcessor(true);
        jsonResolver = new RequestResponseBodyMethodProcessor(messageConverters);
    }

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        RequestBodyParam requestBodyParam = methodParameter.getParameterAnnotation(RequestBodyParam.class);
        if (requestBodyParam != null) contentTypes = CollUtil.newArrayList(requestBodyParam.value());
        return (requestBodyParam != null);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        ServletRequest servletRequest = nativeWebRequest.getNativeRequest(ServletRequest.class);
        String contentType = servletRequest.getContentType();
        if (contentType == null) {
            throw new ServerRuntimeException("不支持的Content-Type类型");
        }
        long count = contentTypes.stream().filter(mediaType -> contentType.contains(mediaType.getValue())).count();
        if (count == 0) throw new ServerRuntimeException("不支持的Content-Type类型");
        if (contentType.contains(ContentType.JSON.getValue())) {
            return jsonResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }
        if (contentType.contains(ContentType.FORM_URLENCODED.getValue())) {
            return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }
        if (contentType.contains(ContentType.MULTIPART.getValue())) {
            return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }
        throw new ServerRuntimeException("不支持的Content-Type类型");
    }
}
